//
// Copyright (c) 2014, 保留所有权利。
//
// MonitorClient.java
//
// 作    者：王红燕
// 当前版本：1.0
// 2015 下午5:24:42
//
// 
//
package com.vanke.agent.tools;

import java.lang.management.ManagementFactory;
import java.lang.management.RuntimeMXBean;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;

import net.sf.json.JSONObject;

import org.apache.log4j.Logger;
import org.apache.thrift.async.AsyncMethodCallback;

import com.common.api.ApiService.AsyncClient.invoke_call;
import com.common.api.AsyncApiClient;
import com.vanke.agent.ADataSource;
import com.vanke.agent.C;
import com.vanke.agent.Cfg;
import com.vanke.agent.bean.Module;
import com.vanke.agent.common.Util;

/**
 *
 */
public class MonitorClient implements Runnable {
	public static void main(String[] args) {
		Connection dbCon = ADataSource.getConnection(ADataSource.SCHEMA_BIZ);
		PreparedStatement pstmt = null;
		ResultSet rs = null;
		String sql = "select `ModuleKey`,`ModuleName`,`Host`,`Pid`,`Status` from sys_Monitor where `ModuleKey`=?";
		try {
			pstmt = dbCon.prepareStatement(sql);
			pstmt.setString(1, "DC.SYNC");
			rs = pstmt.executeQuery();
			if (rs.next()) {
				Module m = new Module();
				m.setKey(rs.getString(1));
				m.setName(rs.getString(2));
				m.setHost(rs.getString(3));
				m.setPid(rs.getString(4));
				m.setStatus(rs.getString(5));
				start(m);
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			ADataSource.close(rs, pstmt, dbCon);
		}
	}

	static Logger log = Logger.getLogger("monitor_client");
	public static final int LOGTYPE_START = 1;
	public static final int LOGTYPE_STOP = 2;
	public static final int LOGTYPE_RUNNING = 3;

	public static final String RUNNING = "运行中";
	public static final String STOPED = "已停止";

	private Module curentModule = null;

	public static List<String> getLocalIPList() {
		List<String> ipList = new ArrayList<String>();
		try {
			Enumeration<NetworkInterface> networkInterfaces = NetworkInterface
					.getNetworkInterfaces();
			NetworkInterface networkInterface;
			Enumeration<InetAddress> inetAddresses;
			InetAddress inetAddress;
			String ip;
			while (networkInterfaces.hasMoreElements()) {
				networkInterface = networkInterfaces.nextElement();
				inetAddresses = networkInterface.getInetAddresses();
				while (inetAddresses.hasMoreElements()) {
					inetAddress = inetAddresses.nextElement();
					if (inetAddress == null) {
						continue;
					}
					if (inetAddress instanceof Inet4Address) { // IPV4
						ip = inetAddress.getHostAddress();
						if (ip.equals("127.0.0.1")) {
							continue;
						}
						ipList.add(ip);
					}
				}
			}
		} catch (SocketException e) {
			e.printStackTrace();
		}
		return ipList;
	}

	public static void start(Module m) {
		if (m == null) {
			log.warn("对应模块未找到");
			return;
		}
		String module = m.getKey();

		List<String> ips = getLocalIPList();
		String host = ips.toString();
		if (host.length() > 1000) {
			host = ips.get(0);
		} else {
			host = host.replace("[", "").replace("]", "");
		}
		RuntimeMXBean rm = ManagementFactory.getRuntimeMXBean();
		String na = rm.getName();
		String pid = na.substring(0, na.indexOf('@'));
		String status = RUNNING;
		m.setPid(pid);
		m.setHost(host);
		m.setStatus(status);
		try {
			JSONObject json = new JSONObject();
			JSONObject header = new JSONObject();
			header.put("cmd", "monitor");
			json.put("header", header);

			json.put("module", module);
			json.put("type", "update_status");

			JSONObject mdata = new JSONObject();
			mdata.put("host", host);
			mdata.put("status", status);
			mdata.put("pid", pid);
			mdata.put("name", m.getName());
			json.put("mdata", mdata);
			reportMessage(json);

			String msg = "进程（" + m.getName() + "）[pid=" + pid + "]" + status;
			log(module, LOGTYPE_START, C.LOG_LEVEL_INFO, "MonitorClient", msg);
		} catch (Exception e) {
			e.printStackTrace();
			log.error("监控服务不可用，无法上报监控数据，停止监控");
			log.error(e);
			return;
		}
		MonitorClient mc = new MonitorClient();
		mc.curentModule = m;
		new Thread(mc).start();
	} //~start(String module)

	public static void log(String module, int type, String level,
			String subName, String msg) {
		JSONObject json = new JSONObject();
		JSONObject header = new JSONObject();
		try {
			header.put("cmd", "monitor");
			json.put("header", header);
			json.put("module", module);
			json.put("type", "log");

			JSONObject mdata = new JSONObject();
			mdata.put("type", type);
			mdata.put("level", level);
			mdata.put("subName", subName);
			mdata.put("msg", msg);
			json.put("mdata", mdata);
			reportMessage(json);
		} catch (Exception e) {
			e.printStackTrace();
			log.error(Util.formatStackTrace(e));
		}
	}

	/**
	 * 检查模块是否正在运行中
	 */
	public static boolean isModuleRunning(String key) {
		Connection dbCon = ADataSource.getConnection(ADataSource.SCHEMA_BIZ);
		PreparedStatement pstmt = null;
		ResultSet rs = null;
		String sql = "select `Status` from sys_Monitor where `ModuleKey`=?";
		try {
			pstmt = dbCon.prepareStatement(sql);
			pstmt.setString(1, key);
			rs = pstmt.executeQuery();
			if (!rs.next()) {
				return false;
			}
			String status = rs.getString(1);
			return RUNNING.equals(status);
		} catch (Exception e) {
			e.printStackTrace();
			log.error(Util.formatStackTrace(e));
		} finally {
			ADataSource.close(rs, pstmt, dbCon);
		}
		return false;
	} //~isRunning

	@Override
	public void run() {
		while (true) {
			try {
				Thread.sleep(3000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			try {
				JSONObject json = new JSONObject();
				JSONObject header = new JSONObject();
				header.put("cmd", "monitor");
				json.put("header", header);
				json.put("module", curentModule.getKey());
				json.put("type", "heart");
				reportMessage(json);
			} catch (Exception e) {
				e.printStackTrace();
				log.error(Util.formatStackTrace(e));
				log.error("监控服务不可用，无法上报监控数据，停止监控");
				break;
			}
		}
	} //~run

	private static void reportMessage(final JSONObject json) throws Exception {
		String monitorAddr = Cfg.get("monitor.service.addr");
		String monitorPort = Cfg.get("monitor.service.port");
		int port = Integer.parseInt(monitorPort);
		try {
			final AsyncApiClient ac = AsyncApiClient.getAsyncClient(
					monitorAddr, port);
			ac.invoke(json.toString(), new AsyncMethodCallback<invoke_call>() {
				@Override
				public void onError(Exception arg0) {
					log.error(Util.formatStackTrace(arg0));
					ac.close();
				}

				@Override
				public void onComplete(invoke_call arg0) {
					ac.close();
				}
			});
		} catch (Exception e) {
			throw e;
		} finally {
		}
	}
}
